#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
KunShan LVControl By PyQt5

author: ZhangAiqiang
website: greatofdream.github.io
Last edited: 2021/10/23
"""
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow,
QWidget,QGridLayout, QAction, QMessageBox, QToolTip, 
QPushButton,QDesktopWidget, QLineEdit,QScrollArea,
QTableWidget,QTableWidgetItem,QHeaderView)
from PyQt5.QtGui import QIcon, QFont, QBrush,QColor
from PyQt5.QtCore import QTimer,QDateTime,QPersistentModelIndex, Qt, pyqtSignal, QThread
import pyqtgraph as pg
import qdarkstyle
import json
from devTest import HVMsg
from database import HVData
import voltage
from time import sleep
from pyqt_led import Led
from functools import partial
class UpCH(QThread):
    signal = pyqtSignal(list)    # 括号里填写信号传递的参数
    def __init__(self, ip, ch=None,t=0):
        super().__init__()
        self.ip = ip
        self.ch = ch
        self.t = t
    def __del__(self):
        self.wait()
 
    def run(self):
        # 进行任务操作
        if self.ch == None:
            sleep(self.t)
            state = voltage.query(self.ip)
        else:
            sleep(self.t)
            state = voltage.queryCh(self.ip, self.ch)
        if state == None:
            state = []
        self.signal.emit(state)
class UpDB(QThread):
    signal = pyqtSignal(list)    # 括号里填写信号传递的参数
    def __init__(self, configs, ips=[]):
        super().__init__()
        self.configs = configs
        self.ips = ips
    def setIps(self, ips):
        self.ips = ips
    def __del__(self):
        self.wait()
    def run(self):
        # 进行任务操作
        alarms = voltage.testAll(self.configs, self.ips)
        # print(state)
        self.signal.emit(alarms)

class LVUI(QMainWindow):
    def __init__(self, configs=None):
        super().__init__()
        self.configs = configs
        self.stacksNum = configs['ip']
        self.stacks = configs['ip']
        self.timer = QTimer()
        self.selectStacks = []
        self.alarms = []
        self.uirows = len(self.stacks)+2+3
        self.autoquery = False
        self.databaseStatus = 0
        self.databaseThread = UpDB(self.configs)
        self.databaseThread.signal.connect(self.ledred)
        self.timer.timeout.connect(self.storeDatabase)
        # 设置绘图背景
        pg.setConfigOption('background', '#19232D')
        pg.setConfigOption('foreground', 'd')
        pg.setConfigOptions(antialias = True)

        # 窗口居中显示
        self.center()
        self.initUI()

        self.setWindowOpacity(0.9) # 设置窗口透明度
        self.main_layout.setSpacing(0)
        # 美化风格
        self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    def connectDataBase(self):
        self.hvdata = HVData(self.configs)
        self.ips = [self.hvdata.getIpByNumber(number) for number in self.stacksNum]
        self.stacks = [self.stacksNum[i]+':'+self.ips[i] for i in range(len(self.stacks))]
        self.updateStackName()
        self.databaseThread.setIps(self.ips)
    def connectLocal(self):
        self.ips = self.configs["defaultIPs"]
        self.stacks = [self.stacksNum[i]+':'+self.ips[i] for i in range(len(self.stacks))]
        self.updateStackName()
        self.databaseThread.setIps(self.ips)
    # def updateIPDataBase(self,number,ip):
    def updateIPDataBase(self):
        ip = self.stackIP.text()
        for i,ss in enumerate(self.stacks):
            if ss.find(self.selectStacks[0])>=0:
                number = self.stacksNum[i]
                break
        print(ip,number)
        self.hvdata.setIpByNumber(number,ip)
    def disconnectDataBase(self):
        # self.hvdata.
        return 0
    def storeDatabase(self):
        self.led.set_on_color(Led.green)
        self.led.turn_on()
        self.databaseThread.start()
    def timerStart(self):
        self.timer.start(120*1000)
        self.led.turn_on()
    def timerStop(self):
        self.databaseThread.quit()
        self.timer.stop()
        self.led.turn_off()
    def ledred(self, alarms):
        # if self.databaseThread.finished():
        self.led.set_on_color(Led.red)
        self.led.turn_on()
        # else:
        #     self.led.set_on_color(Led.red)
        #     self.led.turn_on()
        if alarms!=[]:
            self.alarms += alarms
            self.update_message(self.alarms)
    def clearMessage(self):
        self.alarms = []
        self.update_message(self.alarms)
    def center(self):
        '''
        获取桌面长宽
        获取窗口长宽
        移动
        '''
        self.setGeometry(300, 300, 350, 250)   
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)
    def autoQuery(self):
        if self.autoquery:
            self.autoquery = False
        else:
            self.autoquery = True
    def initUI(self):          
        self.setWindowTitle('低压电源控制 Low Voltage Control')
        self.setWindowIcon(QIcon('static/icon.jpg'))
        self.statusBar = self.statusBar()
        self.statusBar.showMessage('Ready')
        self.statusBar.show()
        self.show()
        # btn = QPushButton('Button', self)
        # btn.setToolTip('<b>打开所有电源</b>')
        # btn.resize(btn.sizeHint())
        # btn.move(50, 50)
        self.initMenu()
        self.initWindow()
    def initMenu(self):
        self.statusBar.showMessage('init menu')
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        connectAct = QAction('Connect', self)
        connectAct.triggered.connect(self.connectDataBase)
        fileMenu.addAction(connectAct)
        disconnectAct = QAction('Disconnect', self)
        disconnectAct.triggered.connect(self.connectDataBase)
        fileMenu.addAction(disconnectAct)
        connectLocalAct = QAction('ConnectLocal', self)
        connectLocalAct.triggered.connect(self.connectLocal)
        fileMenu.addAction(connectLocalAct)
        autoQueryAct = QAction('AutoQuery', self, checkable=True)
        autoQueryAct.setChecked(False)
        autoQueryAct.triggered.connect(self.autoQuery)
        fileMenu.addAction(autoQueryAct)

        recordMenu = menubar.addMenu('&Record')
        startAct = QAction('Start', self)
        startAct.triggered.connect(self.timerStart)
        recordMenu.addAction(startAct)
        stopAct = QAction('Stop', self)
        stopAct.triggered.connect(self.timerStop)
        recordMenu.addAction(stopAct)

        messageMenu = menubar.addMenu('&Message')
        startAct = QAction('Clear', self)
        startAct.triggered.connect(self.clearMessage)
        messageMenu.addAction(startAct)

        self.statusBar.showMessage('finish render menu')
    def initWindow(self):
        # 创建窗口主部件
        self.main_widget = QWidget()  
        # 创建主部件的网格布局
        self.main_layout = QGridLayout()  
        # 设置窗口主部件布局为网格布局
        self.main_widget.setLayout(self.main_layout)  

        # 创建左侧部件
        self.left_widget = QWidget()  
        self.left_widget.setObjectName('left_widget')
        # 创建左侧部件的网格布局层
        self.left_layout = QGridLayout()  
        # 设置左侧部件布局为网格
        self.left_widget.setLayout(self.left_layout) 

        # 创建右侧部件
        self.right_widget = QWidget() 
        self.right_widget.setObjectName('right_widget')
        self.right_layout = QGridLayout()
        self.right_widget.setLayout(self.right_layout) 

        # 左侧部件在第0行第0列，占20行2列
        self.main_layout.addWidget(self.left_widget, 0, 0, 20, 2) 
        # 右侧部件在第0行第6列，占20行10列
        self.main_layout.addWidget(self.right_widget, 0, 5, 20, 10)
        # 设置窗口主部件
        self.setCentralWidget(self.main_widget)

        # 初始化柜子列表
        self.initStacks()
        # 初始化channel列表,
        self.initChs()
        # 初始化监控面板
        self.initMonitor()
    def initCh(self):
        return 0
    def initChs(self):
        # self.scroll = QScrollArea()
        # self.right_layout.addWidget(self.scroll,0,3,17,10)
        self.ChsUI = QTableWidget()
        self.right_layout.addWidget(self.ChsUI,0,3,17,10)
        # self.scroll.setWidget(self.ChsUI)
    def initMonitor(self):
        self.query_result = QTableWidget()
        self.right_layout.addWidget(self.query_result,18,3,3,10)
        self.query_result.setColumnCount(4)
        # 表头自适应收缩
        # self.ChsUI.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        header = ['stack', 'Channel', 'Problem', 'Value']
        self.query_result.setHorizontalHeaderLabels(header)
    def updateStackName(self):
        for i,text in enumerate(self.stacks):
            self.stacksUI[i+1].setText(text)
    def initStacks(self):
        # 柜子编号
        self.stacksUI = [[]]*(len(self.stacks)+2)
        self.stacksUI[0] = QLineEdit()
        for i,text in enumerate(self.stacks):
            self.stacksUI[i+1] = QPushButton(text)
            self.stacksUI[i+1].clicked.connect(self.getInfo)
        self.stacksUI[-1] = QPushButton("total")
        self.stacksUI[-1].clicked.connect(self.getInfo)
        for i in range(len(self.stacks)+2):
            self.left_layout.addWidget(self.stacksUI[i],i+1,0,1,2)
        # 控制按钮
        self.controlUI = [[]]*3
        self.controlUI[0] = QPushButton("Open")
        self.controlUI[1] = QPushButton("Close")
        self.controlUI[2] = QPushButton("Query")
        for i in range(3):
            self.controlUI[i].clicked.connect(self.control)
            self.left_layout.addWidget(self.controlUI[i],self.uirows-i,0,1,1)
        # 更新ip
        self.stackIP = QLineEdit()
        self.left_layout.addWidget(self.stackIP, self.uirows-2,1,1,1)
        self.stackIPBtn = QPushButton("Update IP")
        self.stackIPBtn.clicked.connect(self.updateIPDataBase)
        self.left_layout.addWidget(self.stackIPBtn, self.uirows-1,1,1,1)
        # Record 状况监控
        self.led = Led(self, on_color=Led.red, shape=Led.capsule)
        self.led.setFocusPolicy(Qt.NoFocus)
        self.led.turn_off()
        self.left_layout.addWidget(self.led, self.uirows,1,1,1)
    def closeEvent(self, event):

        reply = QMessageBox.question(self, 'Message',
            "Are you sure to quit?", QMessageBox.Yes | 
            QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()       
    def getInfo(self):
        sender = self.sender()
        self.statusBar.showMessage(sender.text())
        if sender.text()=='total':
            n = len(self.stacks)
            self.selectStacks = [i for i in self.ips]
        else:
            n = 1
            self.selectStacks = [self.sender().text().split(':')[1]]
        self.ChsUI.setRowCount(25*n)
        self.ChsUI.setColumnCount(8)
        # 表头自适应收缩
        # self.ChsUI.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        header = ['stack', 'Channel', 'Voltage', 'Current', 'Master','MSet', 'StandBy', 'SSet']
        self.ChsUI.setHorizontalHeaderLabels(header)
        # self.updateInfo(n, self.selectStacks)
        for i in range(n):
            t = UpCH(self.selectStacks[i])
            t.signal.connect(partial(self.updateInfo,i,self.selectStacks[i]))
            t.start()
        return sender.text()
    def updateInfo(self,i, ip,state):
        # for i in range(n):
        #     state = voltage.query(selectStacks[i])
        for j in range(25):
            item = QTableWidgetItem(ip)
            item.setForeground(QBrush(QColor(144, 182, 240)))
            self.ChsUI.setItem(25*i+j, 0, item)

            item = QTableWidgetItem(str(j+1))
            item.setForeground(QBrush(QColor(144, 182, 240)))
            self.ChsUI.setItem(25*i+j, 1, item)

            item = QTableWidgetItem(str('{:.3f}'.format(state[-1][j][-2])))
            item.setForeground(QBrush(QColor(144, 182, 240)))
            self.ChsUI.setItem(25*i+j, 2, item)

            item = QTableWidgetItem(str('{:.3f}'.format(state[-1][j][-1])))
            item.setForeground(QBrush(QColor(144, 182, 240)))
            self.ChsUI.setItem(25*i+j, 3, item)

            item = QTableWidgetItem(str(state[-1][j][3]))
            item.setForeground(QBrush(QColor(144, 182, 240)))
            self.ChsUI.setItem(25*i+j, 4, item)

            if state[-1][j][3]==1:
                masterState = 'ON'
            else:
                masterState = 'OFF'
            button = QPushButton(masterState)
            self.ChsUI.setCellWidget(25*i+j, 5, button)
            index = QPersistentModelIndex(self.ChsUI.model().index(25*i+j, 5))
            button.clicked.connect(lambda *args,index=index: self.controlCh(index))

            item = QTableWidgetItem(str(state[-1][j][7]))
            item.setForeground(QBrush(QColor(144, 182, 240)))
            self.ChsUI.setItem(25*i+j, 6, item)

            if state[-1][j][7]==1:
                slaveState = 'ON'
            else:
                slaveState = 'OFF'
            button = QPushButton(slaveState)
            self.ChsUI.setCellWidget(25*i+j, 7, button)
            index = QPersistentModelIndex(self.ChsUI.model().index(25*i+j, 7))
            button.clicked.connect(lambda *args,index=index: self.controlChS(index))
    def update_message(self, alarms):
        self.query_result.setRowCount(len(alarms))
        for row in range(len(alarms)):
            for col in range(4):
                item = QTableWidgetItem('')
                item.setForeground(QBrush(QColor(144, 182, 240)))
                self.query_result.setItem(row, col, item)
        for row,al in enumerate(alarms):
            self.query_result.item(row,0).setText(str(al[0]))
            self.query_result.item(row,1).setText(str(al[1]))
            self.query_result.item(row,2).setText(str(al[2]))
            self.query_result.item(row,3).setText(str('{:.3f}'.format(al[3])))
    def setChInfo(self, state, beginN):
        return 0
    def control(self):
        sender = self.sender()
        self.statusBar.showMessage(sender.text()+str(self.selectStacks))
        if len(self.selectStacks)>1:
            n = len(self.selectStacks)
        else:
            n = 1
        for ip in self.selectStacks:
            if self.sender().text()=='Open':
                voltage.control(ip)
                st = 2
            elif self.sender().text()=='Close':
                voltage.control(ip,open=False)
                st = 0.5
        # self.updateInfo(n, self.selectStacks)
        for i in range(n):
            t = UpCH(self.selectStacks[i],t=st)
            t.signal.connect(partial(self.updateInfo,i,self.selectStacks[i]))
            t.start()
        return sender.text()
    # def updateCh(self, row, ip, ch):
    def updateCh(self,row,state):
        # state = voltage.queryCh(ip, ch)
        if state==[]:
            self.statusBar.showMessage('timeout! please manually query state')
            return
        self.ChsUI.item(row,2).setText(str('{:.3f}'.format(state[-2])))
        self.ChsUI.item(row,3).setText(str('{:.3f}'.format(state[-1])))
        self.ChsUI.item(row,4).setText(str(state[3]))
        if state[3]==1:
            masterState = 'ON'
        else:
            masterState = 'OFF'
        button = QPushButton(masterState)
        self.ChsUI.setCellWidget(row, 5, button)
        index = QPersistentModelIndex(self.ChsUI.model().index(row, 5))
        button.clicked.connect(lambda *args,index=index: self.controlCh(index))
        self.ChsUI.item(row,6).setText(str(state[7]))
        if state[7]==1:
            slaveState = 'ON'
        else:
            slaveState = 'OFF'
        button = QPushButton(slaveState)
        self.ChsUI.setCellWidget(row, 7, button)
        index = QPersistentModelIndex(self.ChsUI.model().index(row, 7))
        button.clicked.connect(lambda *args,index=index: self.controlChS(index))
    def controlCh(self,index):
        row = index.row()
        ip = self.ChsUI.item(row,0).text()
        ch = int(self.ChsUI.item(row,1).text())-1
        if self.sender().text()=='OFF':
            voltage.controlCh(ip,ch)
            ts = 0.5
        elif self.sender().text()=='ON':
            voltage.controlCh(ip,ch,open=False)
            ts = 0.5
        print(row)
        # self.updateCh(row, ip, ch)
        # t = threading.Thread(target=self.updateCh, args=(row, ip, ch), name='funciton')
        # t.start()
        if self.autoquery:
            t = UpCH(ip,ch,t=ts)
            t.signal.connect(partial(self.updateCh,row))
            t.start()
        return 0
    def controlChS(self,index):
        row = index.row()
        ip = self.ChsUI.item(row,0).text()
        ch = int(self.ChsUI.item(row,1).text())-1
        if self.sender().text()=='OFF':
            voltage.controlCh(ip,ch,master=False)
            ts = 0.5
        elif self.sender().text()=='ON':
            voltage.controlCh(ip,ch,open=False,master=False)
            ts = 0.5
        print(row)
        # self.updateCh(row, ip, ch)
        # t = threading.Thread(target=self.updateCh, args=(row, ip, ch), name='funciton')
        # t.start()
        if self.autoquery:
            t = UpCH(ip,ch,t=ts)
            t.signal.connect(partial(self.updateCh,row))
            t.start()
        return 0
if __name__ == '__main__':
    with open('./config.json','r') as ipt:
        configs = json.load(ipt)
    app = QApplication(sys.argv)

    ex = LVUI(configs=configs)
    ex.showMaximized()
    sys.exit(app.exec_())